import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
from sklearn import model_selection, preprocessing
from sklearn.linear_model import Ridge, RidgeCV, Lasso, LassoCV, ElasticNet, ElasticNetCV
from sklearn.metrics import mean_squared_error
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler

# 忽略警告
warnings.filterwarnings('ignore')

# 读取 LNC 数据集
LNC = pd.read_excel(r'LNC_data.xlsx')
predictors = LNC.columns[:-1]  # 除目标变量 Y 外的所有列
pca = PCA(n_components=6)

# 划分训练集和测试集
X_train, X_test, y_train, y_test = model_selection.train_test_split(LNC[predictors], LNC['Y'], test_size=0.2, random_state=1)

# PCA 转换
X_pca_train = pca.fit_transform(X_train)
X_pca_test = pca.transform(X_test)
X_train = pd.DataFrame(X_pca_train, columns=['PC1', 'PC2', 'PC3', 'PC4', 'PC5', 'PC6'])  # 使用 PCA 组件名称
X_test = pd.DataFrame(X_pca_test, columns=['PC1', 'PC2', 'PC3', 'PC4', 'PC5', 'PC6'])

# 数据标准化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 图像异常文字数据显示预处理
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False

# 绘制不同特征之间的相关系数图像
a = LNC.iloc[:, :-2].corr()
mask = np.zeros_like(a)
mask[np.tril_indices_from(mask)] = True
plt.figure(figsize=(7, 6))
plt.title('不同特征自相关系数图')
sns.despine(left=True)
sns.heatmap(a, annot=True, fmt=".3g", vmax=1, square=True, cmap='viridis', mask=mask.T)
plt.show()

# 生成不同 Lambda 值
Lambdas = np.logspace(-5, 2, 200)

# 设置存储模型的偏回归系数与 RMSE 参数
ridge_coefficients = []
ridge_error = []
lasso_coefficients = []
lasso_error = []

# 迭代不同的 Lambda 值对应的模型
for Lambda in Lambdas:
    # 数据标准化后建模
    ridge = Ridge(alpha=Lambda)
    ridge.fit(X_train_scaled, y_train)
    ridge_predict = ridge.predict(X_test_scaled)
    RMSE1 = np.sqrt(mean_squared_error(y_test, ridge_predict))
    ridge_error.append(RMSE1)
    ridge_coefficients.append(ridge.coef_)

for Lambda in Lambdas:
    lasso = Lasso(alpha=Lambda, max_iter=10000)
    lasso.fit(X_train_scaled, y_train)
    lasso_predict = lasso.predict(X_test_scaled)
    RMSE2 = np.sqrt(mean_squared_error(y_test, lasso_predict))
    lasso_error.append(RMSE2)
    lasso_coefficients.append(lasso.coef_)

# 绘制岭回归模型不同 Lambda 与回归系数的关系图
plt.figure(figsize=[8, 7])
plt.title('岭回归模型系数与正则化系数关系曲线图')
plt.style.use('ggplot')
for i in range(len(ridge_coefficients[0])):
    plt.plot(Lambdas, [coef[i] for coef in ridge_coefficients], label=f'PC{i+1}')  # 按 PCA 组件绘制
plt.xscale('log')
plt.xlabel('正则化系数 Lambda')
plt.ylabel('岭回归模型系数')
plt.legend(loc='best')
plt.show()

# 绘制 LASSO 模型不同 Lambda 与回归系数的关系图
plt.figure(figsize=[7, 6])
plt.title('LASSO 模型系数与正则化系数关系曲线图')
plt.style.use('ggplot')
for i in range(len(lasso_coefficients[0])):
    plt.plot(Lambdas, [coef[i] for coef in lasso_coefficients], label=f'PC{i+1}')  # 按 PCA 组件绘制
plt.xscale('log')
plt.xlabel('正则化系数 Lambda')
plt.ylabel('LASSO 模型系数')
plt.legend(loc='best')
plt.show()

# 绘制 2 个模型 Lambda 与 RMSE 的关系图
plt.title('岭回归/Lasso模型系数与 RMSE 曲线图')
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
plt.style.use('ggplot')
plt.plot(Lambdas, ridge_error, label='岭回归模型')
plt.plot(Lambdas, lasso_error, label='Lasso 模型')
plt.xscale('log')
plt.xlabel('Lambda')
plt.ylabel('RMSE')
plt.legend(loc='best')
plt.show()

print("-----------------------岭回归模型-----------------")
# 设置交叉验证的参数，对于每一个 Lambda 值，执行 10 折交叉验证
ridge_cv = RidgeCV(alphas=Lambdas, scoring='neg_mean_squared_error', cv=10)
# 模型拟合
ridge_cv.fit(X_train_scaled, y_train)
# 计算每一个模型得分
a = ridge_cv.score(X_train_scaled, y_train)
# 返回最佳的 lambda 值
ridge_best_Lambda = ridge_cv.alpha_
print("岭回归模型最优正则化系数为：" + str(ridge_best_Lambda))

# 基于最佳的 Lambda 值建模
ridge = Ridge(alpha=ridge_best_Lambda)
ridge.fit(X_train_scaled, y_train)
# 返回岭回归系数
print('岭回归模型系数：')
print(pd.Series(index=['Intercept'] + X_train.columns.tolist(), data=[ridge.intercept_] + ridge.coef_.tolist()))

# 测试集验证
ridge_predict = ridge.predict(X_test_scaled)
RMSE = np.sqrt(mean_squared_error(y_test, ridge_predict))
print("岭回归模型均方根误差为:" + str(RMSE))

print("-----------------------Lasso回归模型-----------------")
# LASSO 回归模型的交叉验证
lasso_cv = LassoCV(alphas=Lambdas, n_jobs=-1, cv=10, max_iter=10000)
lasso_cv.fit(X_train_scaled, y_train)
lasso_best_alpha = lasso_cv.alpha_
print("Lasso 模型最优正则化系数为：" + str(lasso_best_alpha))

# 基于最佳的 lambda 值建模
lasso = Lasso(alpha=lasso_best_alpha, max_iter=10000)
lasso.fit(X_train_scaled, y_train)
# 返回 LASSO 回归的系数
print("Lasso 模型回归系数为：")
print(pd.Series(index=['Intercept'] + X_train.columns.tolist(), data=[lasso.intercept_] + lasso.coef_.tolist()))
# 预测
lasso_predict = lasso.predict(X_test_scaled)
# 预测效果验证
RMSE = np.sqrt(mean_squared_error(y_test, lasso_predict))
print("Lasso 模型均方根误差为:" + str(RMSE))
